<!--
 * @Author: liaoyu1992 1519778181@qq.com
 * @Date: 2022-11-04 11:24:35
 * @LastEditors: liaoyu1992 1519778181@qq.com
 * @LastEditTime: 2022-11-11 21:59:49
 * @FilePath: \kgantt\core\components\calendar\Calendar.vue
 * @Description: 日历
-->
<template>
  <g
    class="kgantt-calendar"
    :font-size="fontSize"
    :font-family="fontFamily"
  >
    <rect
      :x="0"
      :y="0"
      :width="columnWidth * dateSetup.dates.length"
      :height="headerHeight"
      class="kgantt-calendarHeader"
    >
    </rect>
    <text
      v-for="item in bottomValues || []"
      :key="item.key"
      :y="item.y"
      :x="item.x"
      :class="item.className"
      :font-family="item.fontFamily ? item.fontFamily : ''"
    >
      {{ item.value }}
    </text>
    <TopPartOfCalendar
      v-for="item in topValues || []"
      :key="item.key"
      :value="item.value"
      :x1Line="item.x1Line"
      :y1Line="item.y1Line"
      :y2Line="item.y2Line"
      :x-text="item.xText"
      :y-text="item.yText"
    ></TopPartOfCalendar>
  </g>
</template>
<script lang="ts" setup>
import { onMounted, PropType, ref, watch } from "vue";
import { ViewMode } from "../../types/publicTypes";
import { DateSetup } from "../../types/dateSetup";
import {
  getCachedDateTimeFormat,
  getDaysInMonth,
  getLocalDayOfWeek,
  getLocaleMonth,
  getWeekNumberISO8601,
} from "../../helpers/dateHelper";
import TopPartOfCalendar from "./TopPartOfCalendar.vue";
const props = defineProps({
  dateSetup: {
    type: Object as PropType<DateSetup>,
    default: {},
  },
  locale: {
    type: String,
    default: "",
  },
  viewMode: {
    type: String as PropType<ViewMode>,
    default: "",
  },
  rtl: {
    type: Boolean,
    default: false,
  },
  headerHeight: {
    type: Number,
    default: 0,
  },
  columnWidth: {
    type: Number,
    default: 0,
  },
  fontFamily: {
    type: String,
    default: "",
  },
  fontSize: {
    type: String,
    default: "",
  },
});
const topValues = ref();
const bottomValues = ref();
const getCalendarValuesForYear = () => {
  const topValuesTmp = [];
  const bottomValuesTmp = [];
  const topDefaultHeight = props.headerHeight * 0.5;
  for (let i = 0; i < props.dateSetup.dates.length; i++) {
    const date = props.dateSetup.dates[i];
    const bottomValue = date.getFullYear();
    bottomValuesTmp.push({
      key: date.getFullYear(),
      x: props.columnWidth * i + props.columnWidth * 0.5,
      y: props.headerHeight * 0.8,
      className: "calendarBottomText",
      value: bottomValue,
    });
    if (
      i === 0 ||
      date.getFullYear() !== props.dateSetup.dates[i - 1].getFullYear()
    ) {
      const topValue = date.getFullYear().toString();
      let xText: number;
      if (props.rtl) {
        xText = (6 + i + date.getFullYear() + 1) * props.columnWidth;
      } else {
        xText = (6 + i - date.getFullYear()) * props.columnWidth;
      }
      topValuesTmp.push({
        key: topValue,
        value: topValue,
        x1Line: props.columnWidth * i,
        y1Line: 0,
        y2Line: props.headerHeight,
        xText: xText,
        yText: topDefaultHeight * 0.9,
      });
    }
  }
  topValues.value = topValuesTmp;
  bottomValues.value = bottomValuesTmp;
};
const getCalendarValuesForMonth = () => {
  const topValuesTmp = [];
  const bottomValuesTmp = [];
  const topDefaultHeight = props.headerHeight * 0.5;
  for (let i = 0; i < props.dateSetup.dates.length; i++) {
    const date = props.dateSetup.dates[i];
    const bottomValue = getLocaleMonth(date, props.locale);
    bottomValuesTmp.push({
      key: bottomValue + date.getFullYear(),
      y: props.headerHeight * 0.8,
      x: props.columnWidth * i + props.columnWidth * 0.5,
      className: "calendarBottomText",
      value: bottomValue,
    });
    if (
      i === 0 ||
      date.getFullYear() !== props.dateSetup.dates[i - 1].getFullYear()
    ) {
      const topValue = date.getFullYear().toString();
      let xText: number;
      if (props.rtl) {
        xText = (6 + i + date.getMonth() + 1) * props.columnWidth;
      } else {
        xText = (6 + i - date.getMonth()) * props.columnWidth;
      }
      topValuesTmp.push({
        key: topValue,
        value: topValue,
        x1Line: props.columnWidth * i,
        y1Line: 0,
        y2Line: topDefaultHeight,
        xText: xText,
        yText: topDefaultHeight * 0.9,
      });
    }
  }
  topValues.value = topValuesTmp;
  bottomValues.value = bottomValuesTmp;
};
const getCalendarValuesForWeek = () => {
  const topValuesTmp = [];
  const bottomValuesTmp = [];
  let weeksCount: number = 1;
  const topDefaultHeight = props.headerHeight * 0.5;
  const dates = props.dateSetup.dates;
  for (let i = dates.length - 1; i >= 0; i--) {
    const date = dates[i];
    let topValue = "";
    if (i === 0 || date.getMonth() !== dates[i - 1].getMonth()) {
      // top
      topValue = `${getLocaleMonth(date, props.locale)}, ${date.getFullYear()}`;
    }
    // bottom
    const bottomValue = `W${getWeekNumberISO8601(date)}`;

    bottomValuesTmp.push({
      key: date.getTime(),
      y: props.headerHeight * 0.8,
      x: props.columnWidth * (i + +props.rtl),
      className: "calendarBottomText",
      value: bottomValue,
    });

    if (topValue) {
      // if last day is new month
      if (i !== dates.length - 1) {
        topValuesTmp.push({
          key: topValue,
          value: topValue,
          x1Line: props.columnWidth * i + weeksCount * props.columnWidth,
          y1Line: 0,
          y2Line: topDefaultHeight,
          xText: props.columnWidth * i + props.columnWidth * weeksCount * 0.5,
          yText: topDefaultHeight * 0.9,
        });
      }
      weeksCount = 0;
    }
    weeksCount++;
  }
  topValues.value = topValuesTmp;
  bottomValues.value = bottomValuesTmp;
};
const getCalendarValuesForDay = () => {
  const topValuesTmp = [];
  const bottomValuesTmp = [];
  const topDefaultHeight = props.headerHeight * 0.5;
  const dates = props.dateSetup.dates;
  for (let i = 0; i < dates.length; i++) {
    const date = dates[i];
    const bottomValue = `${getLocalDayOfWeek(
      date,
      props.locale,
      "short"
    )}, ${date.getDate().toString()}`;

    bottomValuesTmp.push({
      key: date.getTime(),
      y: props.headerHeight * 0.8,
      x: props.columnWidth * i + props.columnWidth * 0.5,
      className: "calendarBottomText",
      value: bottomValue,
    });
    if (i + 1 !== dates.length && date.getMonth() !== dates[i + 1].getMonth()) {
      const topValue = getLocaleMonth(date, props.locale);

      topValuesTmp.push({
        key: topValue + date.getFullYear(),
        value: topValue,
        x1Line: props.columnWidth * (i + 1),
        y1Line: 0,
        y2Line: topDefaultHeight,
        xText:
          props.columnWidth * (i + 1) -
          getDaysInMonth(date.getMonth(), date.getFullYear()) *
            props.columnWidth *
            0.5,
        yText: topDefaultHeight * 0.9,
      });
    }
  }
  topValues.value = topValuesTmp;
  bottomValues.value = bottomValuesTmp;
};
const getCalendarValuesForPartOfDay = () => {
  const topValuesTmp = [];
  const bottomValuesTmp = [];
  const ticks = props.viewMode === ViewMode.HalfDay ? 2 : 4;
  const topDefaultHeight = props.headerHeight * 0.5;
  const dates = props.dateSetup.dates;
  for (let i = 0; i < dates.length; i++) {
    const date = dates[i];
    const bottomValue = getCachedDateTimeFormat(props.locale, {
      hour: "numeric",
    }).format(date);

    bottomValuesTmp.push({
      key: date.getTime(),
      y: props.headerHeight * 0.8,
      x: props.columnWidth * (i + +props.rtl),
      className: "calendarBottomText",
      value: bottomValue,
      fontFamily: props.fontFamily,
    });
    if (i === 0 || date.getDate() !== dates[i - 1].getDate()) {
      const topValue = `${getLocalDayOfWeek(
        date,
        props.locale,
        "short"
      )}, ${date.getDate()} ${getLocaleMonth(date, props.locale)}`;
      topValuesTmp.push({
        key: topValue + date.getFullYear(),
        value: topValue,
        x1Line: props.columnWidth * i + ticks * props.columnWidth,
        y1Line: 0,
        y2Line: topDefaultHeight,
        xText: props.columnWidth * i + ticks * props.columnWidth * 0.5,
        yText: topDefaultHeight * 0.9,
      });
    }
  }
  topValues.value = topValuesTmp;
  bottomValues.value = bottomValuesTmp;
};
const getCalendarValuesForHour = () => {
  const topValuesTmp = [];
  const bottomValuesTmp = [];
  const topDefaultHeight = props.headerHeight * 0.5;
  const dates = props.dateSetup.dates;
  for (let i = 0; i < dates.length; i++) {
    const date = dates[i];
    const bottomValue = getCachedDateTimeFormat(props.locale, {
      hour: "numeric",
    }).format(date);

    bottomValuesTmp.push({
      key: date.getTime(),
      y: props.headerHeight * 0.8,
      x: props.columnWidth * (i + +props.rtl),
      className: "calendarBottomText",
      value: bottomValue,
      fontFamily: props.fontFamily,
    });
    if (i !== 0 && date.getDate() !== dates[i - 1].getDate()) {
      const displayDate = dates[i - 1];
      const topValue = `${getLocalDayOfWeek(
        displayDate,
        props.locale,
        "long"
      )}, ${displayDate.getDate()} ${getLocaleMonth(
        displayDate,
        props.locale
      )}`;
      const topPosition = (date.getHours() - 24) / 2;
      topValuesTmp.push({
        key: topValue + displayDate.getFullYear(),
        value: topValue,
        x1Line: props.columnWidth * i,
        y1Line: 0,
        y2Line: topDefaultHeight,
        xText: props.columnWidth * (i + topPosition),
        yText: topDefaultHeight * 0.9,
      });
    }
  }
  topValues.value = topValuesTmp;
  bottomValues.value = bottomValuesTmp;
};
const updateCalendar = () => {
  switch (props.dateSetup.viewMode) {
    case ViewMode.Year:
      getCalendarValuesForYear();
      break;
    case ViewMode.Month:
      getCalendarValuesForMonth();
      break;
    case ViewMode.Week:
      getCalendarValuesForWeek();
      break;
    case ViewMode.Day:
      getCalendarValuesForDay();
      break;
    case ViewMode.QuarterDay:
    case ViewMode.HalfDay:
      getCalendarValuesForPartOfDay();
      break;
    case ViewMode.Hour:
      getCalendarValuesForHour();
  }
};
watch(()=>props.viewMode,()=>{
  updateCalendar();
});
onMounted(() => {
  updateCalendar();
});
</script>